package com.wg.core.counter;

import cn.hutool.core.date.DateUtil;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 统计管理器，负责管理和监控各类计数器
 *
 * @author 少爷123
 */
public class CounterMgr {
    /**
     * 默认统计间隔时间(秒) - 2分钟
     */
    private final static int DEFAULT_INTERVAL_TIME = 2 * 60;

    /**
     * 处理客户端http请求 平均时间(纳秒)
     */
    private final AverageCounter httpAverage = new AverageCounter();
    /**
     * 处理客户端tcp请求 平均时间(纳秒)
     */
    private final AverageCounter tcpAverage = new AverageCounter();
    /**
     * 处理服务端tcp请求 平均时间(纳秒)
     */
    private final AverageCounter ssAverage = new AverageCounter();
    /**
     * 自定义计数器映射表
     */
    private final Map<String, AverageCounter> customCounters = new ConcurrentHashMap<>();
    /**
     * 上次重置时间
     */
    private volatile long lastResetTime;

    private CounterMgr() {
        httpAverage.setIntervalTime(DEFAULT_INTERVAL_TIME);
        tcpAverage.setIntervalTime(DEFAULT_INTERVAL_TIME);
        ssAverage.setIntervalTime(DEFAULT_INTERVAL_TIME);
        this.lastResetTime = DateUtil.currentSeconds();
    }

    /**
     * 获取单例实例
     *
     * @return CounterMgr实例
     */
    public static CounterMgr getInstance() {
        return Singleton.INSTANCE.getManager();
    }

    /**
     * 获取HTTP请求平均计数器
     *
     * @return HTTP请求平均计数器
     */
    public AverageCounter getHttpAverage() {
        return httpAverage;
    }

    /**
     * 获取TCP请求平均计数器
     *
     * @return TCP请求平均计数器
     */
    public AverageCounter getTcpAverage() {
        return tcpAverage;
    }

    /**
     * 获取服务端间请求平均计数器
     *
     * @return 服务端间请求平均计数器
     */
    public AverageCounter getSsAverage() {
        return ssAverage;
    }

    /**
     * 获取HTTP请求处理平均时间(毫秒)
     *
     * @return HTTP请求处理平均时间(毫秒)
     */
    public long getHttpClientAverageMs() {
        return httpAverage.getAverageValue() / 1000000;
    }

    /**
     * 获取TCP请求处理平均时间(毫秒)
     *
     * @return TCP请求处理平均时间(毫秒)
     */
    public long getTcpClientAverageMs() {
        return tcpAverage.getAverageValue() / 1000000;
    }

    /**
     * 获取服务端间请求处理平均时间(毫秒)
     *
     * @return 服务端间请求处理平均时间(毫秒)
     */
    public long getServerToServerAverageMs() {
        return ssAverage.getAverageValue() / 1000000;
    }

    /**
     * 创建或获取自定义计数器
     *
     * @param name 计数器名称
     * @return 平均计数器
     */
    public AverageCounter getOrCreateCounter(String name) {
        return customCounters.computeIfAbsent(name, k -> {
            AverageCounter counter = new AverageCounter();
            counter.setIntervalTime(DEFAULT_INTERVAL_TIME);
            return counter;
        });
    }

    /**
     * 创建或获取自定义计数器
     *
     * @param name         计数器名称
     * @param intervalTime 间隔时间(秒)
     * @return 平均计数器
     */
    public AverageCounter getOrCreateCounter(String name, long intervalTime) {
        return customCounters.computeIfAbsent(name, k -> {
            AverageCounter counter = new AverageCounter();
            counter.setIntervalTime(intervalTime);
            return counter;
        });
    }

    /**
     * 获取所有自定义计数器
     *
     * @return 自定义计数器映射表
     */
    public Map<String, AverageCounter> getCustomCounters() {
        return Collections.unmodifiableMap(customCounters);
    }

    /**
     * 重置所有计数器
     */
    public void resetAllCounters() {
        httpAverage.reset();
        tcpAverage.reset();
        ssAverage.reset();
        customCounters.values().forEach(AverageCounter::reset);
        this.lastResetTime = DateUtil.currentSeconds();
    }

    /**
     * 获取上次重置时间
     *
     * @return 上次重置时间(秒)
     */
    public long getLastResetTime() {
        return lastResetTime;
    }

    /**
     * 获取所有计数器的统计信息
     *
     * @return 统计信息映射表
     */
    public Map<String, String> getAllStats() {
        Map<String, String> stats = new HashMap<>();
        stats.put("HTTP请求", httpAverage.getStats());
        stats.put("TCP请求", tcpAverage.getStats());
        stats.put("服务端间请求", ssAverage.getStats());
        customCounters.forEach((name, counter) -> stats.put(name, counter.getStats()));
        return stats;
    }

    /**
     * 单例实现
     */
    private enum Singleton {
        INSTANCE;

        CounterMgr manager;

        Singleton() {
            this.manager = new CounterMgr();
        }

        public CounterMgr getManager() {
            return manager;
        }
    }
}
